package handling.channel.handler;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import server.maps.AnimatedMapleMapObject;
import server.movement.*;
import tools.data.input.LittleEndianAccessor;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class MovementParse {

    /**
     * Logger for this class.
     */
    public static final Logger log = LogManager.getLogger(MovementParse.class.getName());

    /*
     * 1 = 玩家移动
     * 2 = 怪物移动
     * 3 = 宠物移动
     * 4 = 召唤兽移动
     * 5 = 龙神龙龙移动
     * 6 = 玩家攻击怪物移动
     * 7 = 小白移动
     */
    public static List<LifeMovementFragment> parseMovement(LittleEndianAccessor lea, int kind) {
        List<LifeMovementFragment> res = new ArrayList<>();
        byte numCommands = lea.readByte(); //循环次数
        for (byte i = 0; i < numCommands; i++) {
            byte command = lea.readByte(); //移动类型
            switch (command) {
                case -1: {
                    short xpos = lea.readShort();
                    short ypos = lea.readShort();
                    short unk = lea.readShort();
                    short fh = lea.readShort(); // 是什么高度
                    byte newstate = lea.readByte(); // 状态姿势
                    short duration = lea.readShort();
                    BounceMovement bm = new BounceMovement(command, new Point(xpos, ypos), duration, newstate);
                    bm.setFH(fh);
                    bm.setUnk(unk);
                    res.add(bm);
                    break;
                }
                case 0:
                case 8:
                case 15:
                case 17:
                case 19:
                case 65:
                case 66:
                case 67:
                case 68:
                case 69:
                case 70:
                case 88: { // 18 size
                    short xpos = lea.readShort();
                    short ypos = lea.readShort();
                    short xwobble = lea.readShort();
                    short ywobble = lea.readShort();
                    short fh = lea.readShort();
                    short sub = command == 15 || command == 17 ? lea.readShort() : 0;
                    short xoffset = lea.readShort();
                    short yoffset = lea.readShort();
                    byte newstate = lea.readByte();
                    short duration = lea.readShort();
                    byte end = lea.readByte();
                    AbsoluteLifeMovement alm = new AbsoluteLifeMovement(command, new Point(xpos, ypos), duration, newstate);
                    alm.setNewFH(fh);
                    alm.setPixelsPerSecond(new Point(xwobble, ywobble));
                    alm.setOffset(new Point(xoffset, yoffset));
                    alm.setSub(sub);
                    alm.setEnd(end);
                    res.add(alm);
                    break;
                }
                case 55:
                case 64:
                case 92: {    // 14 size
                    short xpos = lea.readShort();
                    short ypos = lea.readShort();
                    short xwobble = lea.readShort();
                    short ywobble = lea.readShort();
                    short fh = lea.readShort();
                    byte newstate = lea.readByte();
                    short duration = lea.readShort();
                    byte end = lea.readByte();
                    StaticLifeMovement slm = new StaticLifeMovement(command, new Point(xpos, ypos), duration, newstate);
                    slm.setPixelsPerSecond(new Point(xwobble, ywobble));
                    slm.setNewFH(fh);
                    slm.setEnd(end);
                    res.add(slm);
                    break;
                }
                case 0x01:
                case 0x02:
                case 0x12:
                case 0x18:
                case 0x3C:
                case 0x3D:
                case 0x3E:
                case 0x3F: {    // 8 size
                    short xmod = lea.readShort();
                    short ymod = lea.readShort();
                    byte newstate = lea.readByte();
                    short duration = lea.readShort();
                    byte end = lea.readByte();
                    RelativeLifeMovement rlm = new RelativeLifeMovement(command, new Point(xmod, ymod), duration, newstate);
                    rlm.setEnd(end);
                    res.add(rlm);
                    break;
                }
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 9:
                case 10:
                case 11:
                case 13:
                case 14:
                case 16:
                case 21:
                case 22:
                case 26:
                case 27:
                case 51:
                case 52:
                case 53:
                case 77:
                case 78:
                case 79:
                case 81:
                case 83:
                case 90:
                case 93: {    // 10 size
                    short xpos = lea.readShort();
                    short ypos = lea.readShort();
                    short fh = lea.readShort();
                    byte newstate = lea.readByte();
                    short duration = lea.readShort();
                    byte end = lea.readByte();
                    ChairMovement cm = new ChairMovement(command, new Point(xpos, ypos), duration, newstate);
                    cm.setNewFH(fh);
                    cm.setEnd(end);
                    res.add(cm);
                    break;
                }
                case 0x17: {    // 12 size
                    short xpos = lea.readShort();
                    short ypos = lea.readShort();
                    short xwobble = lea.readShort();
                    short ywobble = lea.readShort();
                    byte newstate = lea.readByte();
                    short duration = lea.readShort();
                    byte end = lea.readByte();
                    TeleportMovement tm = new TeleportMovement(command, new Point(xpos, ypos), duration, newstate);
                    tm.setPixelsPerSecond(new Point(xwobble, ywobble));
                    tm.setEnd(end);
                    res.add(tm);
                    break;
                }
                case 0x30: {    // 6 size
                    short fh = lea.readShort();
                    byte newstate = lea.readByte();
                    short duration = lea.readShort();
                    byte end = lea.readByte();
                    UnknownMovement um = new UnknownMovement(command, new Point(0, 0), duration, newstate);
                    um.setFh(fh);
                    um.setEnd(end);
                    res.add(um);
                    break;
                }
                case 0x0C: {    // 1 size
                    res.add(new ChangeEquipSpecialAwesome(command, lea.readByte()));
                    break;
                }
                case 28:
                case 29:
                case 30:
                case 31:
                case 32:
                case 33:
                case 34:
                case 35:
                case 36:
                case 37:
                case 38:
                case 39:
                case 40:
                case 41:
                case 42:
                case 43:
                case 44:
                case 45:
                case 46:
                case 47:
                case 49:
                case 50:
                case 54:
                case 56:
                case 57:
                case 59:
                case 71:
                case 72:
                case 73:
                case 75:
                case 80:
                case 82:
                case 84:
                case 85:
                case 86:
                case 87: {      // 4 size
                    readAranMovement(lea, res, command);
                    break;
                }
                default: {
                    if (command - 73 > 0 && command - 73 != 2) {
                        readAranMovement(lea, res, command);
                        break;
                    }
                    Unknown2Movement unknown2Movement = new Unknown2Movement(command);
                    for (int j = 0; j < 7; j++) {
                        unknown2Movement.setUnk(j, lea.readShort());
                    }
                    res.add(unknown2Movement);
                }
            }
        }
        double skip = lea.readByteAsInt();
        skip = Math.ceil(skip / 2);
        lea.skip((int) skip);
        if (numCommands != res.size()) {
            log.warn(getKindName(kind) + " 循环次数[" + numCommands + "]和实际上获取的循环次数[" + res.size() + "]不符" + lea.toString(true));
            return null;
        }
        return res;
    }

    public static void readAranMovement(LittleEndianAccessor lea, List<LifeMovementFragment> res, byte command) {
        byte newstate = lea.readByte();
        short duration = lea.readShort();
        byte end = lea.readByte();
        AranMovement am = new AranMovement(command, new Point(0, 0), duration, newstate);
        am.setEnd(end);
        res.add(am);
    }

    public static void updatePosition(List<LifeMovementFragment> movement, AnimatedMapleMapObject target, int yoffset) {
        if (movement == null) {
            return;
        }
        for (LifeMovementFragment move : movement) {
            if (move instanceof LifeMovement) {
                if (move instanceof AbsoluteLifeMovement) {
                    Point position = move.getPosition();
                    position.y += yoffset;
                    target.setPosition(position);
                }
                target.setStance(((LifeMovement) move).getNewstate());
            }
        }
    }

    public static String getKindName(int kind) {
        String moveMsg;
        switch (kind) {
            case 1:
                moveMsg = "玩家";
                break;
            case 2:
                moveMsg = "怪物";
                break;
            case 3:
                moveMsg = "宠物";
                break;
            case 4:
                moveMsg = "召唤兽";
                break;
            case 5:
                moveMsg = "龙龙";
                break;
            case 6:
                moveMsg = "怪怪";
                break;
            case 7:
                moveMsg = "小白";
                break;
            case 8:
                moveMsg = "小白人型";
                break;
            case 9:
                moveMsg = "安卓";
                break;
            default:
                moveMsg = "未知kind";
                break;
        }
        return moveMsg;
    }
}